1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.collect;
16
17 import static com.google.common.base.Preconditions.checkNotNull;
18 import static com.google.common.collect.CollectPreconditions.checkRemove;
19
20 import com.google.common.annotations.VisibleForTesting;
21 import com.google.common.base.Equivalence;
22 import com.google.common.base.Ticker;
23 import com.google.common.collect.GenericMapMaker.NullListener;
24 import com.google.common.collect.MapMaker.RemovalCause;
25 import com.google.common.collect.MapMaker.RemovalListener;
26 import com.google.common.collect.MapMaker.RemovalNotification;
27 import com.google.common.primitives.Ints;
28
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.Serializable;
33 import java.lang.ref.Reference;
34 import java.lang.ref.ReferenceQueue;
35 import java.lang.ref.SoftReference;
36 import java.lang.ref.WeakReference;
37 import java.util.AbstractCollection;
38 import java.util.AbstractMap;
39 import java.util.AbstractQueue;
40 import java.util.AbstractSet;
41 import java.util.Collection;
42 import java.util.Iterator;
43 import java.util.Map;
44 import java.util.NoSuchElementException;
45 import java.util.Queue;
46 import java.util.Set;
47 import java.util.concurrent.CancellationException;
48 import java.util.concurrent.ConcurrentLinkedQueue;
49 import java.util.concurrent.ConcurrentMap;
50 import java.util.concurrent.ExecutionException;
51 import java.util.concurrent.TimeUnit;
52 import java.util.concurrent.atomic.AtomicInteger;
53 import java.util.concurrent.atomic.AtomicReferenceArray;
54 import java.util.concurrent.locks.ReentrantLock;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
57
58 import javax.annotation.Nullable;
59 import javax.annotation.concurrent.GuardedBy;
60
61
62
63
64
65
66
67
68
69
70
71 class MapMakerInternalMap<K, V>
72 extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable {
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 static final int MAXIMUM_CAPACITY = Ints.MAX_POWER_OF_TWO;
108
109
110 static final int MAX_SEGMENTS = 1 << 16;
111
112
113 static final int CONTAINS_VALUE_RETRIES = 3;
114
115
116
117
118
119
120
121
122 static final int DRAIN_THRESHOLD = 0x3F;
123
124
125
126
127
128
129 static final int DRAIN_MAX = 16;
130
131 static final long CLEANUP_EXECUTOR_DELAY_SECS = 60;
132
133
134
135 private static final Logger logger = Logger.getLogger(MapMakerInternalMap.class.getName());
136
137
138
139
140
141 final transient int segmentMask;
142
143
144
145
146
147 final transient int segmentShift;
148
149
150 final transient Segment<K, V>[] segments;
151
152
153 final int concurrencyLevel;
154
155
156 final Equivalence<Object> keyEquivalence;
157
158
159 final Equivalence<Object> valueEquivalence;
160
161
162 final Strength keyStrength;
163
164
165 final Strength valueStrength;
166
167
168 final int maximumSize;
169
170
171 final long expireAfterAccessNanos;
172
173
174 final long expireAfterWriteNanos;
175
176
177
178 final Queue<RemovalNotification<K, V>> removalNotificationQueue;
179
180
181
182
183
184 final RemovalListener<K, V> removalListener;
185
186
187 final transient EntryFactory entryFactory;
188
189
190 final Ticker ticker;
191
192
193
194
195 MapMakerInternalMap(MapMaker builder) {
196 concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
197
198 keyStrength = builder.getKeyStrength();
199 valueStrength = builder.getValueStrength();
200
201 keyEquivalence = builder.getKeyEquivalence();
202 valueEquivalence = valueStrength.defaultEquivalence();
203
204 maximumSize = builder.maximumSize;
205 expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
206 expireAfterWriteNanos = builder.getExpireAfterWriteNanos();
207
208 entryFactory = EntryFactory.getFactory(keyStrength, expires(), evictsBySize());
209 ticker = builder.getTicker();
210
211 removalListener = builder.getRemovalListener();
212 removalNotificationQueue = (removalListener == NullListener.INSTANCE)
213 ? MapMakerInternalMap.<RemovalNotification<K, V>>discardingQueue()
214 : new ConcurrentLinkedQueue<RemovalNotification<K, V>>();
215
216 int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY);
217 if (evictsBySize()) {
218 initialCapacity = Math.min(initialCapacity, maximumSize);
219 }
220
221
222
223
224 int segmentShift = 0;
225 int segmentCount = 1;
226 while (segmentCount < concurrencyLevel
227 && (!evictsBySize() || segmentCount * 2 <= maximumSize)) {
228 ++segmentShift;
229 segmentCount <<= 1;
230 }
231 this.segmentShift = 32 - segmentShift;
232 segmentMask = segmentCount - 1;
233
234 this.segments = newSegmentArray(segmentCount);
235
236 int segmentCapacity = initialCapacity / segmentCount;
237 if (segmentCapacity * segmentCount < initialCapacity) {
238 ++segmentCapacity;
239 }
240
241 int segmentSize = 1;
242 while (segmentSize < segmentCapacity) {
243 segmentSize <<= 1;
244 }
245
246 if (evictsBySize()) {
247
248 int maximumSegmentSize = maximumSize / segmentCount + 1;
249 int remainder = maximumSize % segmentCount;
250 for (int i = 0; i < this.segments.length; ++i) {
251 if (i == remainder) {
252 maximumSegmentSize--;
253 }
254 this.segments[i] =
255 createSegment(segmentSize, maximumSegmentSize);
256 }
257 } else {
258 for (int i = 0; i < this.segments.length; ++i) {
259 this.segments[i] =
260 createSegment(segmentSize, MapMaker.UNSET_INT);
261 }
262 }
263 }
264
265 boolean evictsBySize() {
266 return maximumSize != MapMaker.UNSET_INT;
267 }
268
269 boolean expires() {
270 return expiresAfterWrite() || expiresAfterAccess();
271 }
272
273 boolean expiresAfterWrite() {
274 return expireAfterWriteNanos > 0;
275 }
276
277 boolean expiresAfterAccess() {
278 return expireAfterAccessNanos > 0;
279 }
280
281 boolean usesKeyReferences() {
282 return keyStrength != Strength.STRONG;
283 }
284
285 boolean usesValueReferences() {
286 return valueStrength != Strength.STRONG;
287 }
288
289 enum Strength {
290
291
292
293
294
295 STRONG {
296 @Override
297 <K, V> ValueReference<K, V> referenceValue(
298 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
299 return new StrongValueReference<K, V>(value);
300 }
301
302 @Override
303 Equivalence<Object> defaultEquivalence() {
304 return Equivalence.equals();
305 }
306 },
307
308 SOFT {
309 @Override
310 <K, V> ValueReference<K, V> referenceValue(
311 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
312 return new SoftValueReference<K, V>(segment.valueReferenceQueue, value, entry);
313 }
314
315 @Override
316 Equivalence<Object> defaultEquivalence() {
317 return Equivalence.identity();
318 }
319 },
320
321 WEAK {
322 @Override
323 <K, V> ValueReference<K, V> referenceValue(
324 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
325 return new WeakValueReference<K, V>(segment.valueReferenceQueue, value, entry);
326 }
327
328 @Override
329 Equivalence<Object> defaultEquivalence() {
330 return Equivalence.identity();
331 }
332 };
333
334
335
336
337 abstract <K, V> ValueReference<K, V> referenceValue(
338 Segment<K, V> segment, ReferenceEntry<K, V> entry, V value);
339
340
341
342
343
344
345 abstract Equivalence<Object> defaultEquivalence();
346 }
347
348
349
350
351 enum EntryFactory {
352 STRONG {
353 @Override
354 <K, V> ReferenceEntry<K, V> newEntry(
355 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
356 return new StrongEntry<K, V>(key, hash, next);
357 }
358 },
359 STRONG_EXPIRABLE {
360 @Override
361 <K, V> ReferenceEntry<K, V> newEntry(
362 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
363 return new StrongExpirableEntry<K, V>(key, hash, next);
364 }
365
366 @Override
367 <K, V> ReferenceEntry<K, V> copyEntry(
368 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
369 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
370 copyExpirableEntry(original, newEntry);
371 return newEntry;
372 }
373 },
374 STRONG_EVICTABLE {
375 @Override
376 <K, V> ReferenceEntry<K, V> newEntry(
377 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
378 return new StrongEvictableEntry<K, V>(key, hash, next);
379 }
380
381 @Override
382 <K, V> ReferenceEntry<K, V> copyEntry(
383 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
384 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
385 copyEvictableEntry(original, newEntry);
386 return newEntry;
387 }
388 },
389 STRONG_EXPIRABLE_EVICTABLE {
390 @Override
391 <K, V> ReferenceEntry<K, V> newEntry(
392 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
393 return new StrongExpirableEvictableEntry<K, V>(key, hash, next);
394 }
395
396 @Override
397 <K, V> ReferenceEntry<K, V> copyEntry(
398 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
399 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
400 copyExpirableEntry(original, newEntry);
401 copyEvictableEntry(original, newEntry);
402 return newEntry;
403 }
404 },
405
406 WEAK {
407 @Override
408 <K, V> ReferenceEntry<K, V> newEntry(
409 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
410 return new WeakEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
411 }
412 },
413 WEAK_EXPIRABLE {
414 @Override
415 <K, V> ReferenceEntry<K, V> newEntry(
416 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
417 return new WeakExpirableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
418 }
419
420 @Override
421 <K, V> ReferenceEntry<K, V> copyEntry(
422 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
423 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
424 copyExpirableEntry(original, newEntry);
425 return newEntry;
426 }
427 },
428 WEAK_EVICTABLE {
429 @Override
430 <K, V> ReferenceEntry<K, V> newEntry(
431 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
432 return new WeakEvictableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
433 }
434
435 @Override
436 <K, V> ReferenceEntry<K, V> copyEntry(
437 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
438 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
439 copyEvictableEntry(original, newEntry);
440 return newEntry;
441 }
442 },
443 WEAK_EXPIRABLE_EVICTABLE {
444 @Override
445 <K, V> ReferenceEntry<K, V> newEntry(
446 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
447 return new WeakExpirableEvictableEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
448 }
449
450 @Override
451 <K, V> ReferenceEntry<K, V> copyEntry(
452 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
453 ReferenceEntry<K, V> newEntry = super.copyEntry(segment, original, newNext);
454 copyExpirableEntry(original, newEntry);
455 copyEvictableEntry(original, newEntry);
456 return newEntry;
457 }
458 };
459
460
461
462
463 static final int EXPIRABLE_MASK = 1;
464 static final int EVICTABLE_MASK = 2;
465
466
467
468
469
470 static final EntryFactory[][] factories = {
471 { STRONG, STRONG_EXPIRABLE, STRONG_EVICTABLE, STRONG_EXPIRABLE_EVICTABLE },
472 {},
473 { WEAK, WEAK_EXPIRABLE, WEAK_EVICTABLE, WEAK_EXPIRABLE_EVICTABLE }
474 };
475
476 static EntryFactory getFactory(Strength keyStrength, boolean expireAfterWrite,
477 boolean evictsBySize) {
478 int flags = (expireAfterWrite ? EXPIRABLE_MASK : 0) | (evictsBySize ? EVICTABLE_MASK : 0);
479 return factories[keyStrength.ordinal()][flags];
480 }
481
482
483
484
485
486
487
488
489
490 abstract <K, V> ReferenceEntry<K, V> newEntry(
491 Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next);
492
493
494
495
496
497
498
499
500 <K, V> ReferenceEntry<K, V> copyEntry(
501 Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
502 return newEntry(segment, original.getKey(), original.getHash(), newNext);
503 }
504
505
506 <K, V> void copyExpirableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
507
508
509 newEntry.setExpirationTime(original.getExpirationTime());
510
511 connectExpirables(original.getPreviousExpirable(), newEntry);
512 connectExpirables(newEntry, original.getNextExpirable());
513
514 nullifyExpirable(original);
515 }
516
517
518 <K, V> void copyEvictableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
519
520
521 connectEvictables(original.getPreviousEvictable(), newEntry);
522 connectEvictables(newEntry, original.getNextEvictable());
523
524 nullifyEvictable(original);
525 }
526 }
527
528
529
530
531 interface ValueReference<K, V> {
532
533
534
535 V get();
536
537
538
539
540
541
542
543 V waitForValue() throws ExecutionException;
544
545
546
547
548
549 ReferenceEntry<K, V> getEntry();
550
551
552
553
554
555
556 ValueReference<K, V> copyFor(
557 ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry);
558
559
560
561
562
563
564
565 void clear(@Nullable ValueReference<K, V> newValue);
566
567
568
569
570
571
572 boolean isComputingReference();
573 }
574
575
576
577
578 static final ValueReference<Object, Object> UNSET = new ValueReference<Object, Object>() {
579 @Override
580 public Object get() {
581 return null;
582 }
583
584 @Override
585 public ReferenceEntry<Object, Object> getEntry() {
586 return null;
587 }
588
589 @Override
590 public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue,
591 @Nullable Object value, ReferenceEntry<Object, Object> entry) {
592 return this;
593 }
594
595 @Override
596 public boolean isComputingReference() {
597 return false;
598 }
599
600 @Override
601 public Object waitForValue() {
602 return null;
603 }
604
605 @Override
606 public void clear(ValueReference<Object, Object> newValue) {}
607 };
608
609
610
611
612 @SuppressWarnings("unchecked")
613 static <K, V> ValueReference<K, V> unset() {
614 return (ValueReference<K, V>) UNSET;
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630 interface ReferenceEntry<K, V> {
631
632
633
634 ValueReference<K, V> getValueReference();
635
636
637
638
639 void setValueReference(ValueReference<K, V> valueReference);
640
641
642
643
644 ReferenceEntry<K, V> getNext();
645
646
647
648
649 int getHash();
650
651
652
653
654 K getKey();
655
656
657
658
659
660
661
662
663
664
665 long getExpirationTime();
666
667
668
669
670 void setExpirationTime(long time);
671
672
673
674
675 ReferenceEntry<K, V> getNextExpirable();
676
677
678
679
680 void setNextExpirable(ReferenceEntry<K, V> next);
681
682
683
684
685 ReferenceEntry<K, V> getPreviousExpirable();
686
687
688
689
690 void setPreviousExpirable(ReferenceEntry<K, V> previous);
691
692
693
694
695
696
697
698
699
700
701 ReferenceEntry<K, V> getNextEvictable();
702
703
704
705
706 void setNextEvictable(ReferenceEntry<K, V> next);
707
708
709
710
711 ReferenceEntry<K, V> getPreviousEvictable();
712
713
714
715
716 void setPreviousEvictable(ReferenceEntry<K, V> previous);
717 }
718
719 private enum NullEntry implements ReferenceEntry<Object, Object> {
720 INSTANCE;
721
722 @Override
723 public ValueReference<Object, Object> getValueReference() {
724 return null;
725 }
726
727 @Override
728 public void setValueReference(ValueReference<Object, Object> valueReference) {}
729
730 @Override
731 public ReferenceEntry<Object, Object> getNext() {
732 return null;
733 }
734
735 @Override
736 public int getHash() {
737 return 0;
738 }
739
740 @Override
741 public Object getKey() {
742 return null;
743 }
744
745 @Override
746 public long getExpirationTime() {
747 return 0;
748 }
749
750 @Override
751 public void setExpirationTime(long time) {}
752
753 @Override
754 public ReferenceEntry<Object, Object> getNextExpirable() {
755 return this;
756 }
757
758 @Override
759 public void setNextExpirable(ReferenceEntry<Object, Object> next) {}
760
761 @Override
762 public ReferenceEntry<Object, Object> getPreviousExpirable() {
763 return this;
764 }
765
766 @Override
767 public void setPreviousExpirable(ReferenceEntry<Object, Object> previous) {}
768
769 @Override
770 public ReferenceEntry<Object, Object> getNextEvictable() {
771 return this;
772 }
773
774 @Override
775 public void setNextEvictable(ReferenceEntry<Object, Object> next) {}
776
777 @Override
778 public ReferenceEntry<Object, Object> getPreviousEvictable() {
779 return this;
780 }
781
782 @Override
783 public void setPreviousEvictable(ReferenceEntry<Object, Object> previous) {}
784 }
785
786 abstract static class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> {
787 @Override
788 public ValueReference<K, V> getValueReference() {
789 throw new UnsupportedOperationException();
790 }
791
792 @Override
793 public void setValueReference(ValueReference<K, V> valueReference) {
794 throw new UnsupportedOperationException();
795 }
796
797 @Override
798 public ReferenceEntry<K, V> getNext() {
799 throw new UnsupportedOperationException();
800 }
801
802 @Override
803 public int getHash() {
804 throw new UnsupportedOperationException();
805 }
806
807 @Override
808 public K getKey() {
809 throw new UnsupportedOperationException();
810 }
811
812 @Override
813 public long getExpirationTime() {
814 throw new UnsupportedOperationException();
815 }
816
817 @Override
818 public void setExpirationTime(long time) {
819 throw new UnsupportedOperationException();
820 }
821
822 @Override
823 public ReferenceEntry<K, V> getNextExpirable() {
824 throw new UnsupportedOperationException();
825 }
826
827 @Override
828 public void setNextExpirable(ReferenceEntry<K, V> next) {
829 throw new UnsupportedOperationException();
830 }
831
832 @Override
833 public ReferenceEntry<K, V> getPreviousExpirable() {
834 throw new UnsupportedOperationException();
835 }
836
837 @Override
838 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
839 throw new UnsupportedOperationException();
840 }
841
842 @Override
843 public ReferenceEntry<K, V> getNextEvictable() {
844 throw new UnsupportedOperationException();
845 }
846
847 @Override
848 public void setNextEvictable(ReferenceEntry<K, V> next) {
849 throw new UnsupportedOperationException();
850 }
851
852 @Override
853 public ReferenceEntry<K, V> getPreviousEvictable() {
854 throw new UnsupportedOperationException();
855 }
856
857 @Override
858 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
859 throw new UnsupportedOperationException();
860 }
861 }
862
863 @SuppressWarnings("unchecked")
864 static <K, V> ReferenceEntry<K, V> nullEntry() {
865 return (ReferenceEntry<K, V>) NullEntry.INSTANCE;
866 }
867
868 static final Queue<? extends Object> DISCARDING_QUEUE = new AbstractQueue<Object>() {
869 @Override
870 public boolean offer(Object o) {
871 return true;
872 }
873
874 @Override
875 public Object peek() {
876 return null;
877 }
878
879 @Override
880 public Object poll() {
881 return null;
882 }
883
884 @Override
885 public int size() {
886 return 0;
887 }
888
889 @Override
890 public Iterator<Object> iterator() {
891 return Iterators.emptyIterator();
892 }
893 };
894
895
896
897
898 @SuppressWarnings("unchecked")
899 static <E> Queue<E> discardingQueue() {
900 return (Queue) DISCARDING_QUEUE;
901 }
902
903
904
905
906
907
908
909
910
911
912
913
914 static class StrongEntry<K, V> implements ReferenceEntry<K, V> {
915 final K key;
916
917 StrongEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
918 this.key = key;
919 this.hash = hash;
920 this.next = next;
921 }
922
923 @Override
924 public K getKey() {
925 return this.key;
926 }
927
928
929
930 @Override
931 public long getExpirationTime() {
932 throw new UnsupportedOperationException();
933 }
934
935 @Override
936 public void setExpirationTime(long time) {
937 throw new UnsupportedOperationException();
938 }
939
940 @Override
941 public ReferenceEntry<K, V> getNextExpirable() {
942 throw new UnsupportedOperationException();
943 }
944
945 @Override
946 public void setNextExpirable(ReferenceEntry<K, V> next) {
947 throw new UnsupportedOperationException();
948 }
949
950 @Override
951 public ReferenceEntry<K, V> getPreviousExpirable() {
952 throw new UnsupportedOperationException();
953 }
954
955 @Override
956 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
957 throw new UnsupportedOperationException();
958 }
959
960
961
962 @Override
963 public ReferenceEntry<K, V> getNextEvictable() {
964 throw new UnsupportedOperationException();
965 }
966
967 @Override
968 public void setNextEvictable(ReferenceEntry<K, V> next) {
969 throw new UnsupportedOperationException();
970 }
971
972 @Override
973 public ReferenceEntry<K, V> getPreviousEvictable() {
974 throw new UnsupportedOperationException();
975 }
976
977 @Override
978 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
979 throw new UnsupportedOperationException();
980 }
981
982
983
984 final int hash;
985 final ReferenceEntry<K, V> next;
986 volatile ValueReference<K, V> valueReference = unset();
987
988 @Override
989 public ValueReference<K, V> getValueReference() {
990 return valueReference;
991 }
992
993 @Override
994 public void setValueReference(ValueReference<K, V> valueReference) {
995 ValueReference<K, V> previous = this.valueReference;
996 this.valueReference = valueReference;
997 previous.clear(valueReference);
998 }
999
1000 @Override
1001 public int getHash() {
1002 return hash;
1003 }
1004
1005 @Override
1006 public ReferenceEntry<K, V> getNext() {
1007 return next;
1008 }
1009 }
1010
1011 static final class StrongExpirableEntry<K, V> extends StrongEntry<K, V>
1012 implements ReferenceEntry<K, V> {
1013 StrongExpirableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1014 super(key, hash, next);
1015 }
1016
1017
1018
1019 volatile long time = Long.MAX_VALUE;
1020
1021 @Override
1022 public long getExpirationTime() {
1023 return time;
1024 }
1025
1026 @Override
1027 public void setExpirationTime(long time) {
1028 this.time = time;
1029 }
1030
1031
1032 ReferenceEntry<K, V> nextExpirable = nullEntry();
1033
1034 @Override
1035 public ReferenceEntry<K, V> getNextExpirable() {
1036 return nextExpirable;
1037 }
1038
1039 @Override
1040 public void setNextExpirable(ReferenceEntry<K, V> next) {
1041 this.nextExpirable = next;
1042 }
1043
1044
1045 ReferenceEntry<K, V> previousExpirable = nullEntry();
1046
1047 @Override
1048 public ReferenceEntry<K, V> getPreviousExpirable() {
1049 return previousExpirable;
1050 }
1051
1052 @Override
1053 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1054 this.previousExpirable = previous;
1055 }
1056 }
1057
1058 static final class StrongEvictableEntry<K, V>
1059 extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
1060 StrongEvictableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1061 super(key, hash, next);
1062 }
1063
1064
1065
1066
1067 ReferenceEntry<K, V> nextEvictable = nullEntry();
1068
1069 @Override
1070 public ReferenceEntry<K, V> getNextEvictable() {
1071 return nextEvictable;
1072 }
1073
1074 @Override
1075 public void setNextEvictable(ReferenceEntry<K, V> next) {
1076 this.nextEvictable = next;
1077 }
1078
1079
1080 ReferenceEntry<K, V> previousEvictable = nullEntry();
1081
1082 @Override
1083 public ReferenceEntry<K, V> getPreviousEvictable() {
1084 return previousEvictable;
1085 }
1086
1087 @Override
1088 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1089 this.previousEvictable = previous;
1090 }
1091 }
1092
1093 static final class StrongExpirableEvictableEntry<K, V>
1094 extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
1095 StrongExpirableEvictableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1096 super(key, hash, next);
1097 }
1098
1099
1100
1101 volatile long time = Long.MAX_VALUE;
1102
1103 @Override
1104 public long getExpirationTime() {
1105 return time;
1106 }
1107
1108 @Override
1109 public void setExpirationTime(long time) {
1110 this.time = time;
1111 }
1112
1113
1114 ReferenceEntry<K, V> nextExpirable = nullEntry();
1115
1116 @Override
1117 public ReferenceEntry<K, V> getNextExpirable() {
1118 return nextExpirable;
1119 }
1120
1121 @Override
1122 public void setNextExpirable(ReferenceEntry<K, V> next) {
1123 this.nextExpirable = next;
1124 }
1125
1126
1127 ReferenceEntry<K, V> previousExpirable = nullEntry();
1128
1129 @Override
1130 public ReferenceEntry<K, V> getPreviousExpirable() {
1131 return previousExpirable;
1132 }
1133
1134 @Override
1135 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1136 this.previousExpirable = previous;
1137 }
1138
1139
1140
1141
1142 ReferenceEntry<K, V> nextEvictable = nullEntry();
1143
1144 @Override
1145 public ReferenceEntry<K, V> getNextEvictable() {
1146 return nextEvictable;
1147 }
1148
1149 @Override
1150 public void setNextEvictable(ReferenceEntry<K, V> next) {
1151 this.nextEvictable = next;
1152 }
1153
1154
1155 ReferenceEntry<K, V> previousEvictable = nullEntry();
1156
1157 @Override
1158 public ReferenceEntry<K, V> getPreviousEvictable() {
1159 return previousEvictable;
1160 }
1161
1162 @Override
1163 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1164 this.previousEvictable = previous;
1165 }
1166 }
1167
1168
1169
1170
1171 static class SoftEntry<K, V> extends SoftReference<K> implements ReferenceEntry<K, V> {
1172 SoftEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1173 super(key, queue);
1174 this.hash = hash;
1175 this.next = next;
1176 }
1177
1178 @Override
1179 public K getKey() {
1180 return get();
1181 }
1182
1183
1184 @Override
1185 public long getExpirationTime() {
1186 throw new UnsupportedOperationException();
1187 }
1188
1189 @Override
1190 public void setExpirationTime(long time) {
1191 throw new UnsupportedOperationException();
1192 }
1193
1194 @Override
1195 public ReferenceEntry<K, V> getNextExpirable() {
1196 throw new UnsupportedOperationException();
1197 }
1198
1199 @Override
1200 public void setNextExpirable(ReferenceEntry<K, V> next) {
1201 throw new UnsupportedOperationException();
1202 }
1203
1204 @Override
1205 public ReferenceEntry<K, V> getPreviousExpirable() {
1206 throw new UnsupportedOperationException();
1207 }
1208
1209 @Override
1210 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1211 throw new UnsupportedOperationException();
1212 }
1213
1214
1215
1216 @Override
1217 public ReferenceEntry<K, V> getNextEvictable() {
1218 throw new UnsupportedOperationException();
1219 }
1220
1221 @Override
1222 public void setNextEvictable(ReferenceEntry<K, V> next) {
1223 throw new UnsupportedOperationException();
1224 }
1225
1226 @Override
1227 public ReferenceEntry<K, V> getPreviousEvictable() {
1228 throw new UnsupportedOperationException();
1229 }
1230
1231 @Override
1232 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1233 throw new UnsupportedOperationException();
1234 }
1235
1236
1237
1238 final int hash;
1239 final ReferenceEntry<K, V> next;
1240 volatile ValueReference<K, V> valueReference = unset();
1241
1242 @Override
1243 public ValueReference<K, V> getValueReference() {
1244 return valueReference;
1245 }
1246
1247 @Override
1248 public void setValueReference(ValueReference<K, V> valueReference) {
1249 ValueReference<K, V> previous = this.valueReference;
1250 this.valueReference = valueReference;
1251 previous.clear(valueReference);
1252 }
1253
1254 @Override
1255 public int getHash() {
1256 return hash;
1257 }
1258
1259 @Override
1260 public ReferenceEntry<K, V> getNext() {
1261 return next;
1262 }
1263 }
1264
1265 static final class SoftExpirableEntry<K, V>
1266 extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
1267 SoftExpirableEntry(
1268 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1269 super(queue, key, hash, next);
1270 }
1271
1272
1273
1274 volatile long time = Long.MAX_VALUE;
1275
1276 @Override
1277 public long getExpirationTime() {
1278 return time;
1279 }
1280
1281 @Override
1282 public void setExpirationTime(long time) {
1283 this.time = time;
1284 }
1285
1286
1287 ReferenceEntry<K, V> nextExpirable = nullEntry();
1288
1289 @Override
1290 public ReferenceEntry<K, V> getNextExpirable() {
1291 return nextExpirable;
1292 }
1293
1294 @Override
1295 public void setNextExpirable(ReferenceEntry<K, V> next) {
1296 this.nextExpirable = next;
1297 }
1298
1299
1300 ReferenceEntry<K, V> previousExpirable = nullEntry();
1301
1302 @Override
1303 public ReferenceEntry<K, V> getPreviousExpirable() {
1304 return previousExpirable;
1305 }
1306
1307 @Override
1308 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1309 this.previousExpirable = previous;
1310 }
1311 }
1312
1313 static final class SoftEvictableEntry<K, V>
1314 extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
1315 SoftEvictableEntry(
1316 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1317 super(queue, key, hash, next);
1318 }
1319
1320
1321
1322
1323 ReferenceEntry<K, V> nextEvictable = nullEntry();
1324
1325 @Override
1326 public ReferenceEntry<K, V> getNextEvictable() {
1327 return nextEvictable;
1328 }
1329
1330 @Override
1331 public void setNextEvictable(ReferenceEntry<K, V> next) {
1332 this.nextEvictable = next;
1333 }
1334
1335
1336 ReferenceEntry<K, V> previousEvictable = nullEntry();
1337
1338 @Override
1339 public ReferenceEntry<K, V> getPreviousEvictable() {
1340 return previousEvictable;
1341 }
1342
1343 @Override
1344 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1345 this.previousEvictable = previous;
1346 }
1347 }
1348
1349 static final class SoftExpirableEvictableEntry<K, V>
1350 extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
1351 SoftExpirableEvictableEntry(
1352 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1353 super(queue, key, hash, next);
1354 }
1355
1356
1357
1358 volatile long time = Long.MAX_VALUE;
1359
1360 @Override
1361 public long getExpirationTime() {
1362 return time;
1363 }
1364
1365 @Override
1366 public void setExpirationTime(long time) {
1367 this.time = time;
1368 }
1369
1370
1371 ReferenceEntry<K, V> nextExpirable = nullEntry();
1372
1373 @Override
1374 public ReferenceEntry<K, V> getNextExpirable() {
1375 return nextExpirable;
1376 }
1377
1378 @Override
1379 public void setNextExpirable(ReferenceEntry<K, V> next) {
1380 this.nextExpirable = next;
1381 }
1382
1383
1384 ReferenceEntry<K, V> previousExpirable = nullEntry();
1385
1386 @Override
1387 public ReferenceEntry<K, V> getPreviousExpirable() {
1388 return previousExpirable;
1389 }
1390
1391 @Override
1392 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1393 this.previousExpirable = previous;
1394 }
1395
1396
1397
1398
1399 ReferenceEntry<K, V> nextEvictable = nullEntry();
1400
1401 @Override
1402 public ReferenceEntry<K, V> getNextEvictable() {
1403 return nextEvictable;
1404 }
1405
1406 @Override
1407 public void setNextEvictable(ReferenceEntry<K, V> next) {
1408 this.nextEvictable = next;
1409 }
1410
1411
1412 ReferenceEntry<K, V> previousEvictable = nullEntry();
1413
1414 @Override
1415 public ReferenceEntry<K, V> getPreviousEvictable() {
1416 return previousEvictable;
1417 }
1418
1419 @Override
1420 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1421 this.previousEvictable = previous;
1422 }
1423 }
1424
1425
1426
1427
1428 static class WeakEntry<K, V> extends WeakReference<K> implements ReferenceEntry<K, V> {
1429 WeakEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1430 super(key, queue);
1431 this.hash = hash;
1432 this.next = next;
1433 }
1434
1435 @Override
1436 public K getKey() {
1437 return get();
1438 }
1439
1440
1441
1442 @Override
1443 public long getExpirationTime() {
1444 throw new UnsupportedOperationException();
1445 }
1446
1447 @Override
1448 public void setExpirationTime(long time) {
1449 throw new UnsupportedOperationException();
1450 }
1451
1452 @Override
1453 public ReferenceEntry<K, V> getNextExpirable() {
1454 throw new UnsupportedOperationException();
1455 }
1456
1457 @Override
1458 public void setNextExpirable(ReferenceEntry<K, V> next) {
1459 throw new UnsupportedOperationException();
1460 }
1461
1462 @Override
1463 public ReferenceEntry<K, V> getPreviousExpirable() {
1464 throw new UnsupportedOperationException();
1465 }
1466
1467 @Override
1468 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1469 throw new UnsupportedOperationException();
1470 }
1471
1472
1473
1474 @Override
1475 public ReferenceEntry<K, V> getNextEvictable() {
1476 throw new UnsupportedOperationException();
1477 }
1478
1479 @Override
1480 public void setNextEvictable(ReferenceEntry<K, V> next) {
1481 throw new UnsupportedOperationException();
1482 }
1483
1484 @Override
1485 public ReferenceEntry<K, V> getPreviousEvictable() {
1486 throw new UnsupportedOperationException();
1487 }
1488
1489 @Override
1490 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1491 throw new UnsupportedOperationException();
1492 }
1493
1494
1495
1496 final int hash;
1497 final ReferenceEntry<K, V> next;
1498 volatile ValueReference<K, V> valueReference = unset();
1499
1500 @Override
1501 public ValueReference<K, V> getValueReference() {
1502 return valueReference;
1503 }
1504
1505 @Override
1506 public void setValueReference(ValueReference<K, V> valueReference) {
1507 ValueReference<K, V> previous = this.valueReference;
1508 this.valueReference = valueReference;
1509 previous.clear(valueReference);
1510 }
1511
1512 @Override
1513 public int getHash() {
1514 return hash;
1515 }
1516
1517 @Override
1518 public ReferenceEntry<K, V> getNext() {
1519 return next;
1520 }
1521 }
1522
1523 static final class WeakExpirableEntry<K, V>
1524 extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
1525 WeakExpirableEntry(
1526 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1527 super(queue, key, hash, next);
1528 }
1529
1530
1531
1532 volatile long time = Long.MAX_VALUE;
1533
1534 @Override
1535 public long getExpirationTime() {
1536 return time;
1537 }
1538
1539 @Override
1540 public void setExpirationTime(long time) {
1541 this.time = time;
1542 }
1543
1544
1545 ReferenceEntry<K, V> nextExpirable = nullEntry();
1546
1547 @Override
1548 public ReferenceEntry<K, V> getNextExpirable() {
1549 return nextExpirable;
1550 }
1551
1552 @Override
1553 public void setNextExpirable(ReferenceEntry<K, V> next) {
1554 this.nextExpirable = next;
1555 }
1556
1557
1558 ReferenceEntry<K, V> previousExpirable = nullEntry();
1559
1560 @Override
1561 public ReferenceEntry<K, V> getPreviousExpirable() {
1562 return previousExpirable;
1563 }
1564
1565 @Override
1566 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1567 this.previousExpirable = previous;
1568 }
1569 }
1570
1571 static final class WeakEvictableEntry<K, V>
1572 extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
1573 WeakEvictableEntry(
1574 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1575 super(queue, key, hash, next);
1576 }
1577
1578
1579
1580
1581 ReferenceEntry<K, V> nextEvictable = nullEntry();
1582
1583 @Override
1584 public ReferenceEntry<K, V> getNextEvictable() {
1585 return nextEvictable;
1586 }
1587
1588 @Override
1589 public void setNextEvictable(ReferenceEntry<K, V> next) {
1590 this.nextEvictable = next;
1591 }
1592
1593
1594 ReferenceEntry<K, V> previousEvictable = nullEntry();
1595
1596 @Override
1597 public ReferenceEntry<K, V> getPreviousEvictable() {
1598 return previousEvictable;
1599 }
1600
1601 @Override
1602 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1603 this.previousEvictable = previous;
1604 }
1605 }
1606
1607 static final class WeakExpirableEvictableEntry<K, V>
1608 extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
1609 WeakExpirableEvictableEntry(
1610 ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1611 super(queue, key, hash, next);
1612 }
1613
1614
1615
1616 volatile long time = Long.MAX_VALUE;
1617
1618 @Override
1619 public long getExpirationTime() {
1620 return time;
1621 }
1622
1623 @Override
1624 public void setExpirationTime(long time) {
1625 this.time = time;
1626 }
1627
1628
1629 ReferenceEntry<K, V> nextExpirable = nullEntry();
1630
1631 @Override
1632 public ReferenceEntry<K, V> getNextExpirable() {
1633 return nextExpirable;
1634 }
1635
1636 @Override
1637 public void setNextExpirable(ReferenceEntry<K, V> next) {
1638 this.nextExpirable = next;
1639 }
1640
1641
1642 ReferenceEntry<K, V> previousExpirable = nullEntry();
1643
1644 @Override
1645 public ReferenceEntry<K, V> getPreviousExpirable() {
1646 return previousExpirable;
1647 }
1648
1649 @Override
1650 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
1651 this.previousExpirable = previous;
1652 }
1653
1654
1655
1656
1657 ReferenceEntry<K, V> nextEvictable = nullEntry();
1658
1659 @Override
1660 public ReferenceEntry<K, V> getNextEvictable() {
1661 return nextEvictable;
1662 }
1663
1664 @Override
1665 public void setNextEvictable(ReferenceEntry<K, V> next) {
1666 this.nextEvictable = next;
1667 }
1668
1669
1670 ReferenceEntry<K, V> previousEvictable = nullEntry();
1671
1672 @Override
1673 public ReferenceEntry<K, V> getPreviousEvictable() {
1674 return previousEvictable;
1675 }
1676
1677 @Override
1678 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
1679 this.previousEvictable = previous;
1680 }
1681 }
1682
1683
1684
1685
1686 static final class WeakValueReference<K, V>
1687 extends WeakReference<V> implements ValueReference<K, V> {
1688 final ReferenceEntry<K, V> entry;
1689
1690 WeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
1691 super(referent, queue);
1692 this.entry = entry;
1693 }
1694
1695 @Override
1696 public ReferenceEntry<K, V> getEntry() {
1697 return entry;
1698 }
1699
1700 @Override
1701 public void clear(ValueReference<K, V> newValue) {
1702 clear();
1703 }
1704
1705 @Override
1706 public ValueReference<K, V> copyFor(
1707 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
1708 return new WeakValueReference<K, V>(queue, value, entry);
1709 }
1710
1711 @Override
1712 public boolean isComputingReference() {
1713 return false;
1714 }
1715
1716 @Override
1717 public V waitForValue() {
1718 return get();
1719 }
1720 }
1721
1722
1723
1724
1725 static final class SoftValueReference<K, V>
1726 extends SoftReference<V> implements ValueReference<K, V> {
1727 final ReferenceEntry<K, V> entry;
1728
1729 SoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
1730 super(referent, queue);
1731 this.entry = entry;
1732 }
1733
1734 @Override
1735 public ReferenceEntry<K, V> getEntry() {
1736 return entry;
1737 }
1738
1739 @Override
1740 public void clear(ValueReference<K, V> newValue) {
1741 clear();
1742 }
1743
1744 @Override
1745 public ValueReference<K, V> copyFor(
1746 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
1747 return new SoftValueReference<K, V>(queue, value, entry);
1748 }
1749
1750 @Override
1751 public boolean isComputingReference() {
1752 return false;
1753 }
1754
1755 @Override
1756 public V waitForValue() {
1757 return get();
1758 }
1759 }
1760
1761
1762
1763
1764 static final class StrongValueReference<K, V> implements ValueReference<K, V> {
1765 final V referent;
1766
1767 StrongValueReference(V referent) {
1768 this.referent = referent;
1769 }
1770
1771 @Override
1772 public V get() {
1773 return referent;
1774 }
1775
1776 @Override
1777 public ReferenceEntry<K, V> getEntry() {
1778 return null;
1779 }
1780
1781 @Override
1782 public ValueReference<K, V> copyFor(
1783 ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
1784 return this;
1785 }
1786
1787 @Override
1788 public boolean isComputingReference() {
1789 return false;
1790 }
1791
1792 @Override
1793 public V waitForValue() {
1794 return get();
1795 }
1796
1797 @Override
1798 public void clear(ValueReference<K, V> newValue) {}
1799 }
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809 static int rehash(int h) {
1810
1811
1812
1813 h += (h << 15) ^ 0xffffcd7d;
1814 h ^= (h >>> 10);
1815 h += (h << 3);
1816 h ^= (h >>> 6);
1817 h += (h << 2) + (h << 14);
1818 return h ^ (h >>> 16);
1819 }
1820
1821
1822
1823
1824
1825 @VisibleForTesting
1826 ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
1827 return segmentFor(hash).newEntry(key, hash, next);
1828 }
1829
1830
1831
1832
1833
1834 @VisibleForTesting
1835 ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
1836 int hash = original.getHash();
1837 return segmentFor(hash).copyEntry(original, newNext);
1838 }
1839
1840
1841
1842
1843
1844 @VisibleForTesting
1845 ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value) {
1846 int hash = entry.getHash();
1847 return valueStrength.referenceValue(segmentFor(hash), entry, value);
1848 }
1849
1850 int hash(Object key) {
1851 int h = keyEquivalence.hash(key);
1852 return rehash(h);
1853 }
1854
1855 void reclaimValue(ValueReference<K, V> valueReference) {
1856 ReferenceEntry<K, V> entry = valueReference.getEntry();
1857 int hash = entry.getHash();
1858 segmentFor(hash).reclaimValue(entry.getKey(), hash, valueReference);
1859 }
1860
1861 void reclaimKey(ReferenceEntry<K, V> entry) {
1862 int hash = entry.getHash();
1863 segmentFor(hash).reclaimKey(entry, hash);
1864 }
1865
1866
1867
1868
1869
1870 @VisibleForTesting
1871 boolean isLive(ReferenceEntry<K, V> entry) {
1872 return segmentFor(entry.getHash()).getLiveValue(entry) != null;
1873 }
1874
1875
1876
1877
1878
1879
1880
1881 Segment<K, V> segmentFor(int hash) {
1882
1883 return segments[(hash >>> segmentShift) & segmentMask];
1884 }
1885
1886 Segment<K, V> createSegment(int initialCapacity, int maxSegmentSize) {
1887 return new Segment<K, V>(this, initialCapacity, maxSegmentSize);
1888 }
1889
1890
1891
1892
1893
1894
1895 V getLiveValue(ReferenceEntry<K, V> entry) {
1896 if (entry.getKey() == null) {
1897 return null;
1898 }
1899 V value = entry.getValueReference().get();
1900 if (value == null) {
1901 return null;
1902 }
1903
1904 if (expires() && isExpired(entry)) {
1905 return null;
1906 }
1907 return value;
1908 }
1909
1910
1911
1912
1913
1914
1915 boolean isExpired(ReferenceEntry<K, V> entry) {
1916 return isExpired(entry, ticker.read());
1917 }
1918
1919
1920
1921
1922 boolean isExpired(ReferenceEntry<K, V> entry, long now) {
1923
1924 return now - entry.getExpirationTime() > 0;
1925 }
1926
1927
1928 static <K, V> void connectExpirables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
1929 previous.setNextExpirable(next);
1930 next.setPreviousExpirable(previous);
1931 }
1932
1933
1934 static <K, V> void nullifyExpirable(ReferenceEntry<K, V> nulled) {
1935 ReferenceEntry<K, V> nullEntry = nullEntry();
1936 nulled.setNextExpirable(nullEntry);
1937 nulled.setPreviousExpirable(nullEntry);
1938 }
1939
1940
1941
1942
1943
1944
1945
1946
1947 void processPendingNotifications() {
1948 RemovalNotification<K, V> notification;
1949 while ((notification = removalNotificationQueue.poll()) != null) {
1950 try {
1951 removalListener.onRemoval(notification);
1952 } catch (Exception e) {
1953 logger.log(Level.WARNING, "Exception thrown by removal listener", e);
1954 }
1955 }
1956 }
1957
1958
1959
1960 static <K, V> void connectEvictables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
1961 previous.setNextEvictable(next);
1962 next.setPreviousEvictable(previous);
1963 }
1964
1965
1966 static <K, V> void nullifyEvictable(ReferenceEntry<K, V> nulled) {
1967 ReferenceEntry<K, V> nullEntry = nullEntry();
1968 nulled.setNextEvictable(nullEntry);
1969 nulled.setPreviousEvictable(nullEntry);
1970 }
1971
1972 @SuppressWarnings("unchecked")
1973 final Segment<K, V>[] newSegmentArray(int ssize) {
1974 return new Segment[ssize];
1975 }
1976
1977
1978
1979
1980
1981
1982
1983 @SuppressWarnings("serial")
1984 static class Segment<K, V> extends ReentrantLock {
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019 final MapMakerInternalMap<K, V> map;
2020
2021
2022
2023
2024
2025 volatile int count;
2026
2027
2028
2029
2030
2031
2032
2033 int modCount;
2034
2035
2036
2037
2038
2039 int threshold;
2040
2041
2042
2043
2044 volatile AtomicReferenceArray<ReferenceEntry<K, V>> table;
2045
2046
2047
2048
2049 final int maxSegmentSize;
2050
2051
2052
2053
2054
2055 final ReferenceQueue<K> keyReferenceQueue;
2056
2057
2058
2059
2060
2061 final ReferenceQueue<V> valueReferenceQueue;
2062
2063
2064
2065
2066
2067
2068 final Queue<ReferenceEntry<K, V>> recencyQueue;
2069
2070
2071
2072
2073
2074 final AtomicInteger readCount = new AtomicInteger();
2075
2076
2077
2078
2079
2080 @GuardedBy("Segment.this")
2081 final Queue<ReferenceEntry<K, V>> evictionQueue;
2082
2083
2084
2085
2086
2087 @GuardedBy("Segment.this")
2088 final Queue<ReferenceEntry<K, V>> expirationQueue;
2089
2090 Segment(MapMakerInternalMap<K, V> map, int initialCapacity, int maxSegmentSize) {
2091 this.map = map;
2092 this.maxSegmentSize = maxSegmentSize;
2093 initTable(newEntryArray(initialCapacity));
2094
2095 keyReferenceQueue = map.usesKeyReferences()
2096 ? new ReferenceQueue<K>() : null;
2097
2098 valueReferenceQueue = map.usesValueReferences()
2099 ? new ReferenceQueue<V>() : null;
2100
2101 recencyQueue = (map.evictsBySize() || map.expiresAfterAccess())
2102 ? new ConcurrentLinkedQueue<ReferenceEntry<K, V>>()
2103 : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
2104
2105 evictionQueue = map.evictsBySize()
2106 ? new EvictionQueue<K, V>()
2107 : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
2108
2109 expirationQueue = map.expires()
2110 ? new ExpirationQueue<K, V>()
2111 : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
2112 }
2113
2114 AtomicReferenceArray<ReferenceEntry<K, V>> newEntryArray(int size) {
2115 return new AtomicReferenceArray<ReferenceEntry<K, V>>(size);
2116 }
2117
2118 void initTable(AtomicReferenceArray<ReferenceEntry<K, V>> newTable) {
2119 this.threshold = newTable.length() * 3 / 4;
2120 if (this.threshold == maxSegmentSize) {
2121
2122 this.threshold++;
2123 }
2124 this.table = newTable;
2125 }
2126
2127 @GuardedBy("Segment.this")
2128 ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
2129 return map.entryFactory.newEntry(this, key, hash, next);
2130 }
2131
2132
2133
2134
2135
2136 @GuardedBy("Segment.this")
2137 ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
2138 if (original.getKey() == null) {
2139
2140 return null;
2141 }
2142
2143 ValueReference<K, V> valueReference = original.getValueReference();
2144 V value = valueReference.get();
2145 if ((value == null) && !valueReference.isComputingReference()) {
2146
2147 return null;
2148 }
2149
2150 ReferenceEntry<K, V> newEntry = map.entryFactory.copyEntry(this, original, newNext);
2151 newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, value, newEntry));
2152 return newEntry;
2153 }
2154
2155
2156
2157
2158 @GuardedBy("Segment.this")
2159 void setValue(ReferenceEntry<K, V> entry, V value) {
2160 ValueReference<K, V> valueReference = map.valueStrength.referenceValue(this, entry, value);
2161 entry.setValueReference(valueReference);
2162 recordWrite(entry);
2163 }
2164
2165
2166
2167
2168
2169
2170 void tryDrainReferenceQueues() {
2171 if (tryLock()) {
2172 try {
2173 drainReferenceQueues();
2174 } finally {
2175 unlock();
2176 }
2177 }
2178 }
2179
2180
2181
2182
2183
2184 @GuardedBy("Segment.this")
2185 void drainReferenceQueues() {
2186 if (map.usesKeyReferences()) {
2187 drainKeyReferenceQueue();
2188 }
2189 if (map.usesValueReferences()) {
2190 drainValueReferenceQueue();
2191 }
2192 }
2193
2194 @GuardedBy("Segment.this")
2195 void drainKeyReferenceQueue() {
2196 Reference<? extends K> ref;
2197 int i = 0;
2198 while ((ref = keyReferenceQueue.poll()) != null) {
2199 @SuppressWarnings("unchecked")
2200 ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref;
2201 map.reclaimKey(entry);
2202 if (++i == DRAIN_MAX) {
2203 break;
2204 }
2205 }
2206 }
2207
2208 @GuardedBy("Segment.this")
2209 void drainValueReferenceQueue() {
2210 Reference<? extends V> ref;
2211 int i = 0;
2212 while ((ref = valueReferenceQueue.poll()) != null) {
2213 @SuppressWarnings("unchecked")
2214 ValueReference<K, V> valueReference = (ValueReference<K, V>) ref;
2215 map.reclaimValue(valueReference);
2216 if (++i == DRAIN_MAX) {
2217 break;
2218 }
2219 }
2220 }
2221
2222
2223
2224
2225 void clearReferenceQueues() {
2226 if (map.usesKeyReferences()) {
2227 clearKeyReferenceQueue();
2228 }
2229 if (map.usesValueReferences()) {
2230 clearValueReferenceQueue();
2231 }
2232 }
2233
2234 void clearKeyReferenceQueue() {
2235 while (keyReferenceQueue.poll() != null) {}
2236 }
2237
2238 void clearValueReferenceQueue() {
2239 while (valueReferenceQueue.poll() != null) {}
2240 }
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251 void recordRead(ReferenceEntry<K, V> entry) {
2252 if (map.expiresAfterAccess()) {
2253 recordExpirationTime(entry, map.expireAfterAccessNanos);
2254 }
2255 recencyQueue.add(entry);
2256 }
2257
2258
2259
2260
2261
2262
2263
2264
2265 @GuardedBy("Segment.this")
2266 void recordLockedRead(ReferenceEntry<K, V> entry) {
2267 evictionQueue.add(entry);
2268 if (map.expiresAfterAccess()) {
2269 recordExpirationTime(entry, map.expireAfterAccessNanos);
2270 expirationQueue.add(entry);
2271 }
2272 }
2273
2274
2275
2276
2277
2278 @GuardedBy("Segment.this")
2279 void recordWrite(ReferenceEntry<K, V> entry) {
2280
2281 drainRecencyQueue();
2282 evictionQueue.add(entry);
2283 if (map.expires()) {
2284
2285
2286 long expiration = map.expiresAfterAccess()
2287 ? map.expireAfterAccessNanos
2288 : map.expireAfterWriteNanos;
2289 recordExpirationTime(entry, expiration);
2290 expirationQueue.add(entry);
2291 }
2292 }
2293
2294
2295
2296
2297
2298
2299
2300 @GuardedBy("Segment.this")
2301 void drainRecencyQueue() {
2302 ReferenceEntry<K, V> e;
2303 while ((e = recencyQueue.poll()) != null) {
2304
2305
2306
2307
2308 if (evictionQueue.contains(e)) {
2309 evictionQueue.add(e);
2310 }
2311 if (map.expiresAfterAccess() && expirationQueue.contains(e)) {
2312 expirationQueue.add(e);
2313 }
2314 }
2315 }
2316
2317
2318
2319 void recordExpirationTime(ReferenceEntry<K, V> entry, long expirationNanos) {
2320
2321 entry.setExpirationTime(map.ticker.read() + expirationNanos);
2322 }
2323
2324
2325
2326
2327 void tryExpireEntries() {
2328 if (tryLock()) {
2329 try {
2330 expireEntries();
2331 } finally {
2332 unlock();
2333
2334 }
2335 }
2336 }
2337
2338 @GuardedBy("Segment.this")
2339 void expireEntries() {
2340 drainRecencyQueue();
2341
2342 if (expirationQueue.isEmpty()) {
2343
2344
2345 return;
2346 }
2347 long now = map.ticker.read();
2348 ReferenceEntry<K, V> e;
2349 while ((e = expirationQueue.peek()) != null && map.isExpired(e, now)) {
2350 if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) {
2351 throw new AssertionError();
2352 }
2353 }
2354 }
2355
2356
2357
2358 void enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause) {
2359 enqueueNotification(entry.getKey(), entry.getHash(), entry.getValueReference().get(), cause);
2360 }
2361
2362 void enqueueNotification(@Nullable K key, int hash, @Nullable V value, RemovalCause cause) {
2363 if (map.removalNotificationQueue != DISCARDING_QUEUE) {
2364 RemovalNotification<K, V> notification = new RemovalNotification<K, V>(key, value, cause);
2365 map.removalNotificationQueue.offer(notification);
2366 }
2367 }
2368
2369
2370
2371
2372
2373
2374
2375 @GuardedBy("Segment.this")
2376 boolean evictEntries() {
2377 if (map.evictsBySize() && count >= maxSegmentSize) {
2378 drainRecencyQueue();
2379
2380 ReferenceEntry<K, V> e = evictionQueue.remove();
2381 if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) {
2382 throw new AssertionError();
2383 }
2384 return true;
2385 }
2386 return false;
2387 }
2388
2389
2390
2391
2392 ReferenceEntry<K, V> getFirst(int hash) {
2393
2394 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2395 return table.get(hash & (table.length() - 1));
2396 }
2397
2398
2399
2400 ReferenceEntry<K, V> getEntry(Object key, int hash) {
2401 if (count != 0) {
2402 for (ReferenceEntry<K, V> e = getFirst(hash); e != null; e = e.getNext()) {
2403 if (e.getHash() != hash) {
2404 continue;
2405 }
2406
2407 K entryKey = e.getKey();
2408 if (entryKey == null) {
2409 tryDrainReferenceQueues();
2410 continue;
2411 }
2412
2413 if (map.keyEquivalence.equivalent(key, entryKey)) {
2414 return e;
2415 }
2416 }
2417 }
2418
2419 return null;
2420 }
2421
2422 ReferenceEntry<K, V> getLiveEntry(Object key, int hash) {
2423 ReferenceEntry<K, V> e = getEntry(key, hash);
2424 if (e == null) {
2425 return null;
2426 } else if (map.expires() && map.isExpired(e)) {
2427 tryExpireEntries();
2428 return null;
2429 }
2430 return e;
2431 }
2432
2433 V get(Object key, int hash) {
2434 try {
2435 ReferenceEntry<K, V> e = getLiveEntry(key, hash);
2436 if (e == null) {
2437 return null;
2438 }
2439
2440 V value = e.getValueReference().get();
2441 if (value != null) {
2442 recordRead(e);
2443 } else {
2444 tryDrainReferenceQueues();
2445 }
2446 return value;
2447 } finally {
2448 postReadCleanup();
2449 }
2450 }
2451
2452 boolean containsKey(Object key, int hash) {
2453 try {
2454 if (count != 0) {
2455 ReferenceEntry<K, V> e = getLiveEntry(key, hash);
2456 if (e == null) {
2457 return false;
2458 }
2459 return e.getValueReference().get() != null;
2460 }
2461
2462 return false;
2463 } finally {
2464 postReadCleanup();
2465 }
2466 }
2467
2468
2469
2470
2471
2472 @VisibleForTesting
2473 boolean containsValue(Object value) {
2474 try {
2475 if (count != 0) {
2476 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2477 int length = table.length();
2478 for (int i = 0; i < length; ++i) {
2479 for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
2480 V entryValue = getLiveValue(e);
2481 if (entryValue == null) {
2482 continue;
2483 }
2484 if (map.valueEquivalence.equivalent(value, entryValue)) {
2485 return true;
2486 }
2487 }
2488 }
2489 }
2490
2491 return false;
2492 } finally {
2493 postReadCleanup();
2494 }
2495 }
2496
2497 V put(K key, int hash, V value, boolean onlyIfAbsent) {
2498 lock();
2499 try {
2500 preWriteCleanup();
2501
2502 int newCount = this.count + 1;
2503 if (newCount > this.threshold) {
2504 expand();
2505 newCount = this.count + 1;
2506 }
2507
2508 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2509 int index = hash & (table.length() - 1);
2510 ReferenceEntry<K, V> first = table.get(index);
2511
2512
2513 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2514 K entryKey = e.getKey();
2515 if (e.getHash() == hash && entryKey != null
2516 && map.keyEquivalence.equivalent(key, entryKey)) {
2517
2518
2519 ValueReference<K, V> valueReference = e.getValueReference();
2520 V entryValue = valueReference.get();
2521
2522 if (entryValue == null) {
2523 ++modCount;
2524 setValue(e, value);
2525 if (!valueReference.isComputingReference()) {
2526 enqueueNotification(key, hash, entryValue, RemovalCause.COLLECTED);
2527 newCount = this.count;
2528 } else if (evictEntries()) {
2529 newCount = this.count + 1;
2530 }
2531 this.count = newCount;
2532 return null;
2533 } else if (onlyIfAbsent) {
2534
2535
2536
2537 recordLockedRead(e);
2538 return entryValue;
2539 } else {
2540
2541 ++modCount;
2542 enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
2543 setValue(e, value);
2544 return entryValue;
2545 }
2546 }
2547 }
2548
2549
2550 ++modCount;
2551 ReferenceEntry<K, V> newEntry = newEntry(key, hash, first);
2552 setValue(newEntry, value);
2553 table.set(index, newEntry);
2554 if (evictEntries()) {
2555 newCount = this.count + 1;
2556 }
2557 this.count = newCount;
2558 return null;
2559 } finally {
2560 unlock();
2561 postWriteCleanup();
2562 }
2563 }
2564
2565
2566
2567
2568 @GuardedBy("Segment.this")
2569 void expand() {
2570 AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table;
2571 int oldCapacity = oldTable.length();
2572 if (oldCapacity >= MAXIMUM_CAPACITY) {
2573 return;
2574 }
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586 int newCount = count;
2587 AtomicReferenceArray<ReferenceEntry<K, V>> newTable = newEntryArray(oldCapacity << 1);
2588 threshold = newTable.length() * 3 / 4;
2589 int newMask = newTable.length() - 1;
2590 for (int oldIndex = 0; oldIndex < oldCapacity; ++oldIndex) {
2591
2592
2593 ReferenceEntry<K, V> head = oldTable.get(oldIndex);
2594
2595 if (head != null) {
2596 ReferenceEntry<K, V> next = head.getNext();
2597 int headIndex = head.getHash() & newMask;
2598
2599
2600 if (next == null) {
2601 newTable.set(headIndex, head);
2602 } else {
2603
2604
2605
2606 ReferenceEntry<K, V> tail = head;
2607 int tailIndex = headIndex;
2608 for (ReferenceEntry<K, V> e = next; e != null; e = e.getNext()) {
2609 int newIndex = e.getHash() & newMask;
2610 if (newIndex != tailIndex) {
2611
2612 tailIndex = newIndex;
2613 tail = e;
2614 }
2615 }
2616 newTable.set(tailIndex, tail);
2617
2618
2619 for (ReferenceEntry<K, V> e = head; e != tail; e = e.getNext()) {
2620 int newIndex = e.getHash() & newMask;
2621 ReferenceEntry<K, V> newNext = newTable.get(newIndex);
2622 ReferenceEntry<K, V> newFirst = copyEntry(e, newNext);
2623 if (newFirst != null) {
2624 newTable.set(newIndex, newFirst);
2625 } else {
2626 removeCollectedEntry(e);
2627 newCount--;
2628 }
2629 }
2630 }
2631 }
2632 }
2633 table = newTable;
2634 this.count = newCount;
2635 }
2636
2637 boolean replace(K key, int hash, V oldValue, V newValue) {
2638 lock();
2639 try {
2640 preWriteCleanup();
2641
2642 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2643 int index = hash & (table.length() - 1);
2644 ReferenceEntry<K, V> first = table.get(index);
2645
2646 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2647 K entryKey = e.getKey();
2648 if (e.getHash() == hash && entryKey != null
2649 && map.keyEquivalence.equivalent(key, entryKey)) {
2650
2651
2652 ValueReference<K, V> valueReference = e.getValueReference();
2653 V entryValue = valueReference.get();
2654 if (entryValue == null) {
2655 if (isCollected(valueReference)) {
2656 int newCount = this.count - 1;
2657 ++modCount;
2658 enqueueNotification(entryKey, hash, entryValue, RemovalCause.COLLECTED);
2659 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2660 newCount = this.count - 1;
2661 table.set(index, newFirst);
2662 this.count = newCount;
2663 }
2664 return false;
2665 }
2666
2667 if (map.valueEquivalence.equivalent(oldValue, entryValue)) {
2668 ++modCount;
2669 enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
2670 setValue(e, newValue);
2671 return true;
2672 } else {
2673
2674
2675 recordLockedRead(e);
2676 return false;
2677 }
2678 }
2679 }
2680
2681 return false;
2682 } finally {
2683 unlock();
2684 postWriteCleanup();
2685 }
2686 }
2687
2688 V replace(K key, int hash, V newValue) {
2689 lock();
2690 try {
2691 preWriteCleanup();
2692
2693 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2694 int index = hash & (table.length() - 1);
2695 ReferenceEntry<K, V> first = table.get(index);
2696
2697 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2698 K entryKey = e.getKey();
2699 if (e.getHash() == hash && entryKey != null
2700 && map.keyEquivalence.equivalent(key, entryKey)) {
2701
2702
2703 ValueReference<K, V> valueReference = e.getValueReference();
2704 V entryValue = valueReference.get();
2705 if (entryValue == null) {
2706 if (isCollected(valueReference)) {
2707 int newCount = this.count - 1;
2708 ++modCount;
2709 enqueueNotification(entryKey, hash, entryValue, RemovalCause.COLLECTED);
2710 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2711 newCount = this.count - 1;
2712 table.set(index, newFirst);
2713 this.count = newCount;
2714 }
2715 return null;
2716 }
2717
2718 ++modCount;
2719 enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
2720 setValue(e, newValue);
2721 return entryValue;
2722 }
2723 }
2724
2725 return null;
2726 } finally {
2727 unlock();
2728 postWriteCleanup();
2729 }
2730 }
2731
2732 V remove(Object key, int hash) {
2733 lock();
2734 try {
2735 preWriteCleanup();
2736
2737 int newCount = this.count - 1;
2738 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2739 int index = hash & (table.length() - 1);
2740 ReferenceEntry<K, V> first = table.get(index);
2741
2742 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2743 K entryKey = e.getKey();
2744 if (e.getHash() == hash && entryKey != null
2745 && map.keyEquivalence.equivalent(key, entryKey)) {
2746 ValueReference<K, V> valueReference = e.getValueReference();
2747 V entryValue = valueReference.get();
2748
2749 RemovalCause cause;
2750 if (entryValue != null) {
2751 cause = RemovalCause.EXPLICIT;
2752 } else if (isCollected(valueReference)) {
2753 cause = RemovalCause.COLLECTED;
2754 } else {
2755 return null;
2756 }
2757
2758 ++modCount;
2759 enqueueNotification(entryKey, hash, entryValue, cause);
2760 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2761 newCount = this.count - 1;
2762 table.set(index, newFirst);
2763 this.count = newCount;
2764 return entryValue;
2765 }
2766 }
2767
2768 return null;
2769 } finally {
2770 unlock();
2771 postWriteCleanup();
2772 }
2773 }
2774
2775 boolean remove(Object key, int hash, Object value) {
2776 lock();
2777 try {
2778 preWriteCleanup();
2779
2780 int newCount = this.count - 1;
2781 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2782 int index = hash & (table.length() - 1);
2783 ReferenceEntry<K, V> first = table.get(index);
2784
2785 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2786 K entryKey = e.getKey();
2787 if (e.getHash() == hash && entryKey != null
2788 && map.keyEquivalence.equivalent(key, entryKey)) {
2789 ValueReference<K, V> valueReference = e.getValueReference();
2790 V entryValue = valueReference.get();
2791
2792 RemovalCause cause;
2793 if (map.valueEquivalence.equivalent(value, entryValue)) {
2794 cause = RemovalCause.EXPLICIT;
2795 } else if (isCollected(valueReference)) {
2796 cause = RemovalCause.COLLECTED;
2797 } else {
2798 return false;
2799 }
2800
2801 ++modCount;
2802 enqueueNotification(entryKey, hash, entryValue, cause);
2803 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2804 newCount = this.count - 1;
2805 table.set(index, newFirst);
2806 this.count = newCount;
2807 return (cause == RemovalCause.EXPLICIT);
2808 }
2809 }
2810
2811 return false;
2812 } finally {
2813 unlock();
2814 postWriteCleanup();
2815 }
2816 }
2817
2818 void clear() {
2819 if (count != 0) {
2820 lock();
2821 try {
2822 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2823 if (map.removalNotificationQueue != DISCARDING_QUEUE) {
2824 for (int i = 0; i < table.length(); ++i) {
2825 for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
2826
2827 if (!e.getValueReference().isComputingReference()) {
2828 enqueueNotification(e, RemovalCause.EXPLICIT);
2829 }
2830 }
2831 }
2832 }
2833 for (int i = 0; i < table.length(); ++i) {
2834 table.set(i, null);
2835 }
2836 clearReferenceQueues();
2837 evictionQueue.clear();
2838 expirationQueue.clear();
2839 readCount.set(0);
2840
2841 ++modCount;
2842 count = 0;
2843 } finally {
2844 unlock();
2845 postWriteCleanup();
2846 }
2847 }
2848 }
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862 @GuardedBy("Segment.this")
2863 ReferenceEntry<K, V> removeFromChain(ReferenceEntry<K, V> first, ReferenceEntry<K, V> entry) {
2864 evictionQueue.remove(entry);
2865 expirationQueue.remove(entry);
2866
2867 int newCount = count;
2868 ReferenceEntry<K, V> newFirst = entry.getNext();
2869 for (ReferenceEntry<K, V> e = first; e != entry; e = e.getNext()) {
2870 ReferenceEntry<K, V> next = copyEntry(e, newFirst);
2871 if (next != null) {
2872 newFirst = next;
2873 } else {
2874 removeCollectedEntry(e);
2875 newCount--;
2876 }
2877 }
2878 this.count = newCount;
2879 return newFirst;
2880 }
2881
2882 void removeCollectedEntry(ReferenceEntry<K, V> entry) {
2883 enqueueNotification(entry, RemovalCause.COLLECTED);
2884 evictionQueue.remove(entry);
2885 expirationQueue.remove(entry);
2886 }
2887
2888
2889
2890
2891 boolean reclaimKey(ReferenceEntry<K, V> entry, int hash) {
2892 lock();
2893 try {
2894 int newCount = count - 1;
2895 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2896 int index = hash & (table.length() - 1);
2897 ReferenceEntry<K, V> first = table.get(index);
2898
2899 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2900 if (e == entry) {
2901 ++modCount;
2902 enqueueNotification(
2903 e.getKey(), hash, e.getValueReference().get(), RemovalCause.COLLECTED);
2904 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2905 newCount = this.count - 1;
2906 table.set(index, newFirst);
2907 this.count = newCount;
2908 return true;
2909 }
2910 }
2911
2912 return false;
2913 } finally {
2914 unlock();
2915 postWriteCleanup();
2916 }
2917 }
2918
2919
2920
2921
2922 boolean reclaimValue(K key, int hash, ValueReference<K, V> valueReference) {
2923 lock();
2924 try {
2925 int newCount = this.count - 1;
2926 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2927 int index = hash & (table.length() - 1);
2928 ReferenceEntry<K, V> first = table.get(index);
2929
2930 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2931 K entryKey = e.getKey();
2932 if (e.getHash() == hash && entryKey != null
2933 && map.keyEquivalence.equivalent(key, entryKey)) {
2934 ValueReference<K, V> v = e.getValueReference();
2935 if (v == valueReference) {
2936 ++modCount;
2937 enqueueNotification(key, hash, valueReference.get(), RemovalCause.COLLECTED);
2938 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2939 newCount = this.count - 1;
2940 table.set(index, newFirst);
2941 this.count = newCount;
2942 return true;
2943 }
2944 return false;
2945 }
2946 }
2947
2948 return false;
2949 } finally {
2950 unlock();
2951 if (!isHeldByCurrentThread()) {
2952 postWriteCleanup();
2953 }
2954 }
2955 }
2956
2957
2958
2959
2960 boolean clearValue(K key, int hash, ValueReference<K, V> valueReference) {
2961 lock();
2962 try {
2963 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2964 int index = hash & (table.length() - 1);
2965 ReferenceEntry<K, V> first = table.get(index);
2966
2967 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2968 K entryKey = e.getKey();
2969 if (e.getHash() == hash && entryKey != null
2970 && map.keyEquivalence.equivalent(key, entryKey)) {
2971 ValueReference<K, V> v = e.getValueReference();
2972 if (v == valueReference) {
2973 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
2974 table.set(index, newFirst);
2975 return true;
2976 }
2977 return false;
2978 }
2979 }
2980
2981 return false;
2982 } finally {
2983 unlock();
2984 postWriteCleanup();
2985 }
2986 }
2987
2988 @GuardedBy("Segment.this")
2989 boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) {
2990 int newCount = this.count - 1;
2991 AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
2992 int index = hash & (table.length() - 1);
2993 ReferenceEntry<K, V> first = table.get(index);
2994
2995 for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
2996 if (e == entry) {
2997 ++modCount;
2998 enqueueNotification(e.getKey(), hash, e.getValueReference().get(), cause);
2999 ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
3000 newCount = this.count - 1;
3001 table.set(index, newFirst);
3002 this.count = newCount;
3003 return true;
3004 }
3005 }
3006
3007 return false;
3008 }
3009
3010
3011
3012
3013
3014 boolean isCollected(ValueReference<K, V> valueReference) {
3015 if (valueReference.isComputingReference()) {
3016 return false;
3017 }
3018 return (valueReference.get() == null);
3019 }
3020
3021
3022
3023
3024
3025 V getLiveValue(ReferenceEntry<K, V> entry) {
3026 if (entry.getKey() == null) {
3027 tryDrainReferenceQueues();
3028 return null;
3029 }
3030 V value = entry.getValueReference().get();
3031 if (value == null) {
3032 tryDrainReferenceQueues();
3033 return null;
3034 }
3035
3036 if (map.expires() && map.isExpired(entry)) {
3037 tryExpireEntries();
3038 return null;
3039 }
3040 return value;
3041 }
3042
3043
3044
3045
3046
3047
3048 void postReadCleanup() {
3049 if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) {
3050 runCleanup();
3051 }
3052 }
3053
3054
3055
3056
3057
3058
3059
3060 @GuardedBy("Segment.this")
3061 void preWriteCleanup() {
3062 runLockedCleanup();
3063 }
3064
3065
3066
3067
3068 void postWriteCleanup() {
3069 runUnlockedCleanup();
3070 }
3071
3072 void runCleanup() {
3073 runLockedCleanup();
3074 runUnlockedCleanup();
3075 }
3076
3077 void runLockedCleanup() {
3078 if (tryLock()) {
3079 try {
3080 drainReferenceQueues();
3081 expireEntries();
3082 readCount.set(0);
3083 } finally {
3084 unlock();
3085 }
3086 }
3087 }
3088
3089 void runUnlockedCleanup() {
3090
3091 if (!isHeldByCurrentThread()) {
3092 map.processPendingNotifications();
3093 }
3094 }
3095
3096 }
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111 static final class EvictionQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
3112 final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
3113
3114 ReferenceEntry<K, V> nextEvictable = this;
3115
3116 @Override
3117 public ReferenceEntry<K, V> getNextEvictable() {
3118 return nextEvictable;
3119 }
3120
3121 @Override
3122 public void setNextEvictable(ReferenceEntry<K, V> next) {
3123 this.nextEvictable = next;
3124 }
3125
3126 ReferenceEntry<K, V> previousEvictable = this;
3127
3128 @Override
3129 public ReferenceEntry<K, V> getPreviousEvictable() {
3130 return previousEvictable;
3131 }
3132
3133 @Override
3134 public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
3135 this.previousEvictable = previous;
3136 }
3137 };
3138
3139
3140
3141 @Override
3142 public boolean offer(ReferenceEntry<K, V> entry) {
3143
3144 connectEvictables(entry.getPreviousEvictable(), entry.getNextEvictable());
3145
3146
3147 connectEvictables(head.getPreviousEvictable(), entry);
3148 connectEvictables(entry, head);
3149
3150 return true;
3151 }
3152
3153 @Override
3154 public ReferenceEntry<K, V> peek() {
3155 ReferenceEntry<K, V> next = head.getNextEvictable();
3156 return (next == head) ? null : next;
3157 }
3158
3159 @Override
3160 public ReferenceEntry<K, V> poll() {
3161 ReferenceEntry<K, V> next = head.getNextEvictable();
3162 if (next == head) {
3163 return null;
3164 }
3165
3166 remove(next);
3167 return next;
3168 }
3169
3170 @Override
3171 @SuppressWarnings("unchecked")
3172 public boolean remove(Object o) {
3173 ReferenceEntry<K, V> e = (ReferenceEntry) o;
3174 ReferenceEntry<K, V> previous = e.getPreviousEvictable();
3175 ReferenceEntry<K, V> next = e.getNextEvictable();
3176 connectEvictables(previous, next);
3177 nullifyEvictable(e);
3178
3179 return next != NullEntry.INSTANCE;
3180 }
3181
3182 @Override
3183 @SuppressWarnings("unchecked")
3184 public boolean contains(Object o) {
3185 ReferenceEntry<K, V> e = (ReferenceEntry) o;
3186 return e.getNextEvictable() != NullEntry.INSTANCE;
3187 }
3188
3189 @Override
3190 public boolean isEmpty() {
3191 return head.getNextEvictable() == head;
3192 }
3193
3194 @Override
3195 public int size() {
3196 int size = 0;
3197 for (ReferenceEntry<K, V> e = head.getNextEvictable(); e != head; e = e.getNextEvictable()) {
3198 size++;
3199 }
3200 return size;
3201 }
3202
3203 @Override
3204 public void clear() {
3205 ReferenceEntry<K, V> e = head.getNextEvictable();
3206 while (e != head) {
3207 ReferenceEntry<K, V> next = e.getNextEvictable();
3208 nullifyEvictable(e);
3209 e = next;
3210 }
3211
3212 head.setNextEvictable(head);
3213 head.setPreviousEvictable(head);
3214 }
3215
3216 @Override
3217 public Iterator<ReferenceEntry<K, V>> iterator() {
3218 return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
3219 @Override
3220 protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
3221 ReferenceEntry<K, V> next = previous.getNextEvictable();
3222 return (next == head) ? null : next;
3223 }
3224 };
3225 }
3226 }
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239 static final class ExpirationQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
3240 final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
3241
3242 @Override
3243 public long getExpirationTime() {
3244 return Long.MAX_VALUE;
3245 }
3246
3247 @Override
3248 public void setExpirationTime(long time) {}
3249
3250 ReferenceEntry<K, V> nextExpirable = this;
3251
3252 @Override
3253 public ReferenceEntry<K, V> getNextExpirable() {
3254 return nextExpirable;
3255 }
3256
3257 @Override
3258 public void setNextExpirable(ReferenceEntry<K, V> next) {
3259 this.nextExpirable = next;
3260 }
3261
3262 ReferenceEntry<K, V> previousExpirable = this;
3263
3264 @Override
3265 public ReferenceEntry<K, V> getPreviousExpirable() {
3266 return previousExpirable;
3267 }
3268
3269 @Override
3270 public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
3271 this.previousExpirable = previous;
3272 }
3273 };
3274
3275
3276
3277 @Override
3278 public boolean offer(ReferenceEntry<K, V> entry) {
3279
3280 connectExpirables(entry.getPreviousExpirable(), entry.getNextExpirable());
3281
3282
3283 connectExpirables(head.getPreviousExpirable(), entry);
3284 connectExpirables(entry, head);
3285
3286 return true;
3287 }
3288
3289 @Override
3290 public ReferenceEntry<K, V> peek() {
3291 ReferenceEntry<K, V> next = head.getNextExpirable();
3292 return (next == head) ? null : next;
3293 }
3294
3295 @Override
3296 public ReferenceEntry<K, V> poll() {
3297 ReferenceEntry<K, V> next = head.getNextExpirable();
3298 if (next == head) {
3299 return null;
3300 }
3301
3302 remove(next);
3303 return next;
3304 }
3305
3306 @Override
3307 @SuppressWarnings("unchecked")
3308 public boolean remove(Object o) {
3309 ReferenceEntry<K, V> e = (ReferenceEntry) o;
3310 ReferenceEntry<K, V> previous = e.getPreviousExpirable();
3311 ReferenceEntry<K, V> next = e.getNextExpirable();
3312 connectExpirables(previous, next);
3313 nullifyExpirable(e);
3314
3315 return next != NullEntry.INSTANCE;
3316 }
3317
3318 @Override
3319 @SuppressWarnings("unchecked")
3320 public boolean contains(Object o) {
3321 ReferenceEntry<K, V> e = (ReferenceEntry) o;
3322 return e.getNextExpirable() != NullEntry.INSTANCE;
3323 }
3324
3325 @Override
3326 public boolean isEmpty() {
3327 return head.getNextExpirable() == head;
3328 }
3329
3330 @Override
3331 public int size() {
3332 int size = 0;
3333 for (ReferenceEntry<K, V> e = head.getNextExpirable(); e != head; e = e.getNextExpirable()) {
3334 size++;
3335 }
3336 return size;
3337 }
3338
3339 @Override
3340 public void clear() {
3341 ReferenceEntry<K, V> e = head.getNextExpirable();
3342 while (e != head) {
3343 ReferenceEntry<K, V> next = e.getNextExpirable();
3344 nullifyExpirable(e);
3345 e = next;
3346 }
3347
3348 head.setNextExpirable(head);
3349 head.setPreviousExpirable(head);
3350 }
3351
3352 @Override
3353 public Iterator<ReferenceEntry<K, V>> iterator() {
3354 return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
3355 @Override
3356 protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
3357 ReferenceEntry<K, V> next = previous.getNextExpirable();
3358 return (next == head) ? null : next;
3359 }
3360 };
3361 }
3362 }
3363
3364 static final class CleanupMapTask implements Runnable {
3365 final WeakReference<MapMakerInternalMap<?, ?>> mapReference;
3366
3367 public CleanupMapTask(MapMakerInternalMap<?, ?> map) {
3368 this.mapReference = new WeakReference<MapMakerInternalMap<?, ?>>(map);
3369 }
3370
3371 @Override
3372 public void run() {
3373 MapMakerInternalMap<?, ?> map = mapReference.get();
3374 if (map == null) {
3375 throw new CancellationException();
3376 }
3377
3378 for (Segment<?, ?> segment : map.segments) {
3379 segment.runCleanup();
3380 }
3381 }
3382 }
3383
3384
3385
3386 @Override
3387 public boolean isEmpty() {
3388
3389
3390
3391
3392
3393
3394
3395 long sum = 0L;
3396 Segment<K, V>[] segments = this.segments;
3397 for (int i = 0; i < segments.length; ++i) {
3398 if (segments[i].count != 0) {
3399 return false;
3400 }
3401 sum += segments[i].modCount;
3402 }
3403
3404 if (sum != 0L) {
3405 for (int i = 0; i < segments.length; ++i) {
3406 if (segments[i].count != 0) {
3407 return false;
3408 }
3409 sum -= segments[i].modCount;
3410 }
3411 if (sum != 0L) {
3412 return false;
3413 }
3414 }
3415 return true;
3416 }
3417
3418 @Override
3419 public int size() {
3420 Segment<K, V>[] segments = this.segments;
3421 long sum = 0;
3422 for (int i = 0; i < segments.length; ++i) {
3423 sum += segments[i].count;
3424 }
3425 return Ints.saturatedCast(sum);
3426 }
3427
3428 @Override
3429 public V get(@Nullable Object key) {
3430 if (key == null) {
3431 return null;
3432 }
3433 int hash = hash(key);
3434 return segmentFor(hash).get(key, hash);
3435 }
3436
3437
3438
3439
3440
3441 ReferenceEntry<K, V> getEntry(@Nullable Object key) {
3442 if (key == null) {
3443 return null;
3444 }
3445 int hash = hash(key);
3446 return segmentFor(hash).getEntry(key, hash);
3447 }
3448
3449 @Override
3450 public boolean containsKey(@Nullable Object key) {
3451 if (key == null) {
3452 return false;
3453 }
3454 int hash = hash(key);
3455 return segmentFor(hash).containsKey(key, hash);
3456 }
3457
3458 @Override
3459 public boolean containsValue(@Nullable Object value) {
3460 if (value == null) {
3461 return false;
3462 }
3463
3464
3465
3466
3467
3468
3469 final Segment<K, V>[] segments = this.segments;
3470 long last = -1L;
3471 for (int i = 0; i < CONTAINS_VALUE_RETRIES; i++) {
3472 long sum = 0L;
3473 for (Segment<K, V> segment : segments) {
3474
3475 @SuppressWarnings({"UnusedDeclaration", "unused"})
3476 int c = segment.count;
3477
3478 AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table;
3479 for (int j = 0; j < table.length(); j++) {
3480 for (ReferenceEntry<K, V> e = table.get(j); e != null; e = e.getNext()) {
3481 V v = segment.getLiveValue(e);
3482 if (v != null && valueEquivalence.equivalent(value, v)) {
3483 return true;
3484 }
3485 }
3486 }
3487 sum += segment.modCount;
3488 }
3489 if (sum == last) {
3490 break;
3491 }
3492 last = sum;
3493 }
3494 return false;
3495 }
3496
3497 @Override
3498 public V put(K key, V value) {
3499 checkNotNull(key);
3500 checkNotNull(value);
3501 int hash = hash(key);
3502 return segmentFor(hash).put(key, hash, value, false);
3503 }
3504
3505 @Override
3506 public V putIfAbsent(K key, V value) {
3507 checkNotNull(key);
3508 checkNotNull(value);
3509 int hash = hash(key);
3510 return segmentFor(hash).put(key, hash, value, true);
3511 }
3512
3513 @Override
3514 public void putAll(Map<? extends K, ? extends V> m) {
3515 for (Entry<? extends K, ? extends V> e : m.entrySet()) {
3516 put(e.getKey(), e.getValue());
3517 }
3518 }
3519
3520 @Override
3521 public V remove(@Nullable Object key) {
3522 if (key == null) {
3523 return null;
3524 }
3525 int hash = hash(key);
3526 return segmentFor(hash).remove(key, hash);
3527 }
3528
3529 @Override
3530 public boolean remove(@Nullable Object key, @Nullable Object value) {
3531 if (key == null || value == null) {
3532 return false;
3533 }
3534 int hash = hash(key);
3535 return segmentFor(hash).remove(key, hash, value);
3536 }
3537
3538 @Override
3539 public boolean replace(K key, @Nullable V oldValue, V newValue) {
3540 checkNotNull(key);
3541 checkNotNull(newValue);
3542 if (oldValue == null) {
3543 return false;
3544 }
3545 int hash = hash(key);
3546 return segmentFor(hash).replace(key, hash, oldValue, newValue);
3547 }
3548
3549 @Override
3550 public V replace(K key, V value) {
3551 checkNotNull(key);
3552 checkNotNull(value);
3553 int hash = hash(key);
3554 return segmentFor(hash).replace(key, hash, value);
3555 }
3556
3557 @Override
3558 public void clear() {
3559 for (Segment<K, V> segment : segments) {
3560 segment.clear();
3561 }
3562 }
3563
3564 transient Set<K> keySet;
3565
3566 @Override
3567 public Set<K> keySet() {
3568 Set<K> ks = keySet;
3569 return (ks != null) ? ks : (keySet = new KeySet());
3570 }
3571
3572 transient Collection<V> values;
3573
3574 @Override
3575 public Collection<V> values() {
3576 Collection<V> vs = values;
3577 return (vs != null) ? vs : (values = new Values());
3578 }
3579
3580 transient Set<Entry<K, V>> entrySet;
3581
3582 @Override
3583 public Set<Entry<K, V>> entrySet() {
3584 Set<Entry<K, V>> es = entrySet;
3585 return (es != null) ? es : (entrySet = new EntrySet());
3586 }
3587
3588
3589
3590 abstract class HashIterator<E> implements Iterator<E> {
3591
3592 int nextSegmentIndex;
3593 int nextTableIndex;
3594 Segment<K, V> currentSegment;
3595 AtomicReferenceArray<ReferenceEntry<K, V>> currentTable;
3596 ReferenceEntry<K, V> nextEntry;
3597 WriteThroughEntry nextExternal;
3598 WriteThroughEntry lastReturned;
3599
3600 HashIterator() {
3601 nextSegmentIndex = segments.length - 1;
3602 nextTableIndex = -1;
3603 advance();
3604 }
3605
3606 @Override
3607 public abstract E next();
3608
3609 final void advance() {
3610 nextExternal = null;
3611
3612 if (nextInChain()) {
3613 return;
3614 }
3615
3616 if (nextInTable()) {
3617 return;
3618 }
3619
3620 while (nextSegmentIndex >= 0) {
3621 currentSegment = segments[nextSegmentIndex--];
3622 if (currentSegment.count != 0) {
3623 currentTable = currentSegment.table;
3624 nextTableIndex = currentTable.length() - 1;
3625 if (nextInTable()) {
3626 return;
3627 }
3628 }
3629 }
3630 }
3631
3632
3633
3634
3635 boolean nextInChain() {
3636 if (nextEntry != null) {
3637 for (nextEntry = nextEntry.getNext(); nextEntry != null; nextEntry = nextEntry.getNext()) {
3638 if (advanceTo(nextEntry)) {
3639 return true;
3640 }
3641 }
3642 }
3643 return false;
3644 }
3645
3646
3647
3648
3649 boolean nextInTable() {
3650 while (nextTableIndex >= 0) {
3651 if ((nextEntry = currentTable.get(nextTableIndex--)) != null) {
3652 if (advanceTo(nextEntry) || nextInChain()) {
3653 return true;
3654 }
3655 }
3656 }
3657 return false;
3658 }
3659
3660
3661
3662
3663
3664 boolean advanceTo(ReferenceEntry<K, V> entry) {
3665 try {
3666 K key = entry.getKey();
3667 V value = getLiveValue(entry);
3668 if (value != null) {
3669 nextExternal = new WriteThroughEntry(key, value);
3670 return true;
3671 } else {
3672
3673 return false;
3674 }
3675 } finally {
3676 currentSegment.postReadCleanup();
3677 }
3678 }
3679
3680 @Override
3681 public boolean hasNext() {
3682 return nextExternal != null;
3683 }
3684
3685 WriteThroughEntry nextEntry() {
3686 if (nextExternal == null) {
3687 throw new NoSuchElementException();
3688 }
3689 lastReturned = nextExternal;
3690 advance();
3691 return lastReturned;
3692 }
3693
3694 @Override
3695 public void remove() {
3696 checkRemove(lastReturned != null);
3697 MapMakerInternalMap.this.remove(lastReturned.getKey());
3698 lastReturned = null;
3699 }
3700 }
3701
3702 final class KeyIterator extends HashIterator<K> {
3703
3704 @Override
3705 public K next() {
3706 return nextEntry().getKey();
3707 }
3708 }
3709
3710 final class ValueIterator extends HashIterator<V> {
3711
3712 @Override
3713 public V next() {
3714 return nextEntry().getValue();
3715 }
3716 }
3717
3718
3719
3720
3721
3722 final class WriteThroughEntry extends AbstractMapEntry<K, V> {
3723 final K key;
3724 V value;
3725
3726 WriteThroughEntry(K key, V value) {
3727 this.key = key;
3728 this.value = value;
3729 }
3730
3731 @Override
3732 public K getKey() {
3733 return key;
3734 }
3735
3736 @Override
3737 public V getValue() {
3738 return value;
3739 }
3740
3741 @Override
3742 public boolean equals(@Nullable Object object) {
3743
3744 if (object instanceof Entry) {
3745 Entry<?, ?> that = (Entry<?, ?>) object;
3746 return key.equals(that.getKey()) && value.equals(that.getValue());
3747 }
3748 return false;
3749 }
3750
3751 @Override
3752 public int hashCode() {
3753
3754 return key.hashCode() ^ value.hashCode();
3755 }
3756
3757 @Override
3758 public V setValue(V newValue) {
3759 V oldValue = put(key, newValue);
3760 value = newValue;
3761 return oldValue;
3762 }
3763 }
3764
3765 final class EntryIterator extends HashIterator<Entry<K, V>> {
3766
3767 @Override
3768 public Entry<K, V> next() {
3769 return nextEntry();
3770 }
3771 }
3772
3773 final class KeySet extends AbstractSet<K> {
3774
3775 @Override
3776 public Iterator<K> iterator() {
3777 return new KeyIterator();
3778 }
3779
3780 @Override
3781 public int size() {
3782 return MapMakerInternalMap.this.size();
3783 }
3784
3785 @Override
3786 public boolean isEmpty() {
3787 return MapMakerInternalMap.this.isEmpty();
3788 }
3789
3790 @Override
3791 public boolean contains(Object o) {
3792 return MapMakerInternalMap.this.containsKey(o);
3793 }
3794
3795 @Override
3796 public boolean remove(Object o) {
3797 return MapMakerInternalMap.this.remove(o) != null;
3798 }
3799
3800 @Override
3801 public void clear() {
3802 MapMakerInternalMap.this.clear();
3803 }
3804 }
3805
3806 final class Values extends AbstractCollection<V> {
3807
3808 @Override
3809 public Iterator<V> iterator() {
3810 return new ValueIterator();
3811 }
3812
3813 @Override
3814 public int size() {
3815 return MapMakerInternalMap.this.size();
3816 }
3817
3818 @Override
3819 public boolean isEmpty() {
3820 return MapMakerInternalMap.this.isEmpty();
3821 }
3822
3823 @Override
3824 public boolean contains(Object o) {
3825 return MapMakerInternalMap.this.containsValue(o);
3826 }
3827
3828 @Override
3829 public void clear() {
3830 MapMakerInternalMap.this.clear();
3831 }
3832 }
3833
3834 final class EntrySet extends AbstractSet<Entry<K, V>> {
3835
3836 @Override
3837 public Iterator<Entry<K, V>> iterator() {
3838 return new EntryIterator();
3839 }
3840
3841 @Override
3842 public boolean contains(Object o) {
3843 if (!(o instanceof Entry)) {
3844 return false;
3845 }
3846 Entry<?, ?> e = (Entry<?, ?>) o;
3847 Object key = e.getKey();
3848 if (key == null) {
3849 return false;
3850 }
3851 V v = MapMakerInternalMap.this.get(key);
3852
3853 return v != null && valueEquivalence.equivalent(e.getValue(), v);
3854 }
3855
3856 @Override
3857 public boolean remove(Object o) {
3858 if (!(o instanceof Entry)) {
3859 return false;
3860 }
3861 Entry<?, ?> e = (Entry<?, ?>) o;
3862 Object key = e.getKey();
3863 return key != null && MapMakerInternalMap.this.remove(key, e.getValue());
3864 }
3865
3866 @Override
3867 public int size() {
3868 return MapMakerInternalMap.this.size();
3869 }
3870
3871 @Override
3872 public boolean isEmpty() {
3873 return MapMakerInternalMap.this.isEmpty();
3874 }
3875
3876 @Override
3877 public void clear() {
3878 MapMakerInternalMap.this.clear();
3879 }
3880 }
3881
3882
3883
3884 private static final long serialVersionUID = 5;
3885
3886 Object writeReplace() {
3887 return new SerializationProxy<K, V>(keyStrength, valueStrength, keyEquivalence,
3888 valueEquivalence, expireAfterWriteNanos, expireAfterAccessNanos, maximumSize,
3889 concurrencyLevel, removalListener, this);
3890 }
3891
3892
3893
3894
3895
3896 abstract static class AbstractSerializationProxy<K, V>
3897 extends ForwardingConcurrentMap<K, V> implements Serializable {
3898 private static final long serialVersionUID = 3;
3899
3900 final Strength keyStrength;
3901 final Strength valueStrength;
3902 final Equivalence<Object> keyEquivalence;
3903 final Equivalence<Object> valueEquivalence;
3904 final long expireAfterWriteNanos;
3905 final long expireAfterAccessNanos;
3906 final int maximumSize;
3907 final int concurrencyLevel;
3908 final RemovalListener<? super K, ? super V> removalListener;
3909
3910 transient ConcurrentMap<K, V> delegate;
3911
3912 AbstractSerializationProxy(Strength keyStrength, Strength valueStrength,
3913 Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
3914 long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
3915 int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
3916 ConcurrentMap<K, V> delegate) {
3917 this.keyStrength = keyStrength;
3918 this.valueStrength = valueStrength;
3919 this.keyEquivalence = keyEquivalence;
3920 this.valueEquivalence = valueEquivalence;
3921 this.expireAfterWriteNanos = expireAfterWriteNanos;
3922 this.expireAfterAccessNanos = expireAfterAccessNanos;
3923 this.maximumSize = maximumSize;
3924 this.concurrencyLevel = concurrencyLevel;
3925 this.removalListener = removalListener;
3926 this.delegate = delegate;
3927 }
3928
3929 @Override
3930 protected ConcurrentMap<K, V> delegate() {
3931 return delegate;
3932 }
3933
3934 void writeMapTo(ObjectOutputStream out) throws IOException {
3935 out.writeInt(delegate.size());
3936 for (Entry<K, V> entry : delegate.entrySet()) {
3937 out.writeObject(entry.getKey());
3938 out.writeObject(entry.getValue());
3939 }
3940 out.writeObject(null);
3941 }
3942
3943 @SuppressWarnings("deprecation")
3944 MapMaker readMapMaker(ObjectInputStream in) throws IOException {
3945 int size = in.readInt();
3946 MapMaker mapMaker = new MapMaker()
3947 .initialCapacity(size)
3948 .setKeyStrength(keyStrength)
3949 .setValueStrength(valueStrength)
3950 .keyEquivalence(keyEquivalence)
3951 .concurrencyLevel(concurrencyLevel);
3952 mapMaker.removalListener(removalListener);
3953 if (expireAfterWriteNanos > 0) {
3954 mapMaker.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS);
3955 }
3956 if (expireAfterAccessNanos > 0) {
3957 mapMaker.expireAfterAccess(expireAfterAccessNanos, TimeUnit.NANOSECONDS);
3958 }
3959 if (maximumSize != MapMaker.UNSET_INT) {
3960 mapMaker.maximumSize(maximumSize);
3961 }
3962 return mapMaker;
3963 }
3964
3965 @SuppressWarnings("unchecked")
3966 void readEntries(ObjectInputStream in) throws IOException, ClassNotFoundException {
3967 while (true) {
3968 K key = (K) in.readObject();
3969 if (key == null) {
3970 break;
3971 }
3972 V value = (V) in.readObject();
3973 delegate.put(key, value);
3974 }
3975 }
3976 }
3977
3978
3979
3980
3981
3982 private static final class SerializationProxy<K, V> extends AbstractSerializationProxy<K, V> {
3983 private static final long serialVersionUID = 3;
3984
3985 SerializationProxy(Strength keyStrength, Strength valueStrength,
3986 Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
3987 long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
3988 int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
3989 ConcurrentMap<K, V> delegate) {
3990 super(keyStrength, valueStrength, keyEquivalence, valueEquivalence, expireAfterWriteNanos,
3991 expireAfterAccessNanos, maximumSize, concurrencyLevel, removalListener, delegate);
3992 }
3993
3994 private void writeObject(ObjectOutputStream out) throws IOException {
3995 out.defaultWriteObject();
3996 writeMapTo(out);
3997 }
3998
3999 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
4000 in.defaultReadObject();
4001 MapMaker mapMaker = readMapMaker(in);
4002 delegate = mapMaker.makeMap();
4003 readEntries(in);
4004 }
4005
4006 private Object readResolve() {
4007 return delegate;
4008 }
4009 }
4010 }